/*
 * cat1.c
 *
 *  Created on: Sep 14, 2021
 *      Author: soliber
 */
#include "cat1.h"
#include "hmi.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string.h>
#include "core_json.h"
#include "saveconfig.h"
#include "app_version.h"

#define MAX(a,b) ((a)>(b)?(a):(b))
#define MIN(a,b) ((a)<(b)?(a):(b))

//AT指令回显
#ifdef AT_ECHO
#define AT_TX_ECHO(format,...)	DEBUG_PRINT("\r\n[AT_TX_ECHO]\r\n"format"[AT_TX_ECHO_END]\r\n",##__VA_ARGS__)
#define AT_RX_ECHO(format,...)	DEBUG_PRINT("\r\n[AT_RX_ECHO]\r\n"format"[AT_RX_ECHO_END]\r\n",##__VA_ARGS__)
#else
#define AT_TX_ECHO(format,...)
#define AT_RX_ECHO(format,...)
#endif

//指令发送buffer
#define CAT1_TX_BUFFER_SIZE 1024
static char cat1_tx_buf[CAT1_TX_BUFFER_SIZE];

//接收响应所用的Buffer定义、计数
#define CAT1_RX_BUFFER_SIZE 1024
static char cat1_rx_buf[CAT1_RX_BUFFER_SIZE];
static uint16_t rx_cnt;

//信号质量
#define RSSI_MIN 15	//信号质量最低阀值
#define RSSI_MAX 31	//信号质量最低阀值

//MQTT客户端配置
const char CLIENT_ID[] = "0"SID;
const char USER_NAME[] = "0"SID;
const char PASSWORD[] = "testPassword";
//Broker连接配置
const char BROKER_HOST[] = "www.hlink.info";
const int BROKER_PORT = 1883;
//Topic
const char DEVICE_PUB_TOPIC[] = "sub/0"SID;
const char DEVICE_SUB_TOPIC[] = "pub/0"SID;
//发布消息
const char MSG_DEVICE_ONLINE[] = "{\\\\22deviceId\\\\22:"SID"}";

//发布消息队列
osMessageQDef(publish_q,10,char*);
osMessageQId publish_q_id;

//允许发布，用于互斥的变量
uint8_t publish_enable = 0;

/* 基本指令收发 */

/**
 * @brief 向CAT1模块发送指令，并接收响应
 * 
 * @note 接收过程中该线程将阻塞，直到接收到足够多的数据（行）或接收超时
 * 
 * @param cmd 要发送的字符串，如果为NULL则仅接收
 * @param timeout 最大接收超时时间
 *
 * @return char* 接收到的响应字符串
 */
char * cat1_cmd(const char cmd[], uint32_t timeout)
{
	HAL_StatusTypeDef st;
	//开始DMA发送指令
	if(cmd)
	{
		st = HAL_BUSY;
		uint8_t cnt = 0;
		while(st == HAL_BUSY&&cnt<5)
		{
			st = HAL_UART_Transmit_DMA(&huart2,(uint8_t*)cmd,strlen(cmd));
			cnt++;
			osDelay(1);
		}
		if(st != HAL_OK)
		{
			//发送错误
			PRINT("DMA send error in cat1_cmd()\r\n");
			Error_Handler();
		}
		if(cnt >= 5)
		{
			PRINT("DMA is too BUSY!\r\n");
		}
	}
	
	//开始接收响应
	rx_cnt = 0;
	st = HAL_UARTEx_ReceiveToIdle_DMA(&huart2, (uint8_t*)cat1_rx_buf, CAT1_RX_BUFFER_SIZE);
	if(st != HAL_OK)
	{
		//接收错误
		PRINT("DMA receive error\r\n");
		Error_Handler();
	}

	//阻塞等待接收完成
	osEvent evt = osSignalWait(CAT1_SIGNAL_RX_CPLT,timeout);

	//接收完成
	if(evt.status == osEventSignal){}
	//信号超时
	else if(evt.status == osEventTimeout)
	{
		//终止接收
		HAL_UART_AbortReceive(&huart2);
	}
	//不应该有其他的情况
	else
	{
		Error_Handler();
	}

	//已接收的数据必须有结束符
	cat1_rx_buf[ MIN(rx_cnt,CAT1_RX_BUFFER_SIZE-1)] = '\0';

	if(cmd)AT_TX_ECHO("%s",cat1_tx_buf);
	AT_RX_ECHO("%s",cat1_rx_buf);

	return cat1_rx_buf;
}

/**
 * @brief 向CAT1模块发送指令，并接收窗口时间内的响应
 *
 * @note 接收过程中该线程将阻塞，直到超时
 *
 * @param cmd 要发送的字符串，如果为NULL则仅接收
 * @param timeout 最大接收超时时间
 *
 * @return char* 接收到的响应字符串
 */
char * cat1_cmd_to(const char cmd[], uint32_t timeout)
{
	HAL_StatusTypeDef st;
	//开始DMA发送指令
	if(cmd)
	{
		st = HAL_BUSY;
		uint8_t cnt = 0;
		while(st == HAL_BUSY&&cnt<5)
		{
			st = HAL_UART_Transmit_DMA(&huart2,(uint8_t*)cmd,strlen(cmd));
			cnt++;
			osDelay(1);
		}
		if(st != HAL_OK)
		{
			//发送错误
			PRINT("DMA send error in cat1_cmd_to()\r\n");
			Error_Handler();
		}
		if(cnt >= 5)
		{
			PRINT("DMA is too BUSY!\r\n");
		}
	}

	//开始接收响应
	st = HAL_UART_Receive_DMA(&huart2, (uint8_t*)cat1_rx_buf, CAT1_RX_BUFFER_SIZE);
//	st = HAL_UARTEx_ReceiveToIdle_DMA(&huart2, (uint8_t*)cat1_rx_buf, CAT1_RX_BUFFER_SIZE);
	if(st != HAL_OK)
	{
		//接收错误
		Error_Handler();
	}

	//阻塞等待接收完成
	osEvent evt = osSignalWait(CAT1_SIGNAL_RX_CPLT,timeout);

	//接收完成
	if(evt.status == osEventSignal && evt.value.signals == CAT1_SIGNAL_RX_CPLT)
	{
		//数据量太大，buffer已满
		rx_cnt = CAT1_RX_BUFFER_SIZE;
	}
	//其他情况
	else
	{
		//记录已接收到数据量
		rx_cnt = CAT1_RX_BUFFER_SIZE - __HAL_DMA_GET_COUNTER(huart2.hdmarx);
		//终止接收
		HAL_UART_AbortReceive(&huart2);
	}


	//已接收的数据必须有结束符
	cat1_rx_buf[ MIN(rx_cnt,CAT1_RX_BUFFER_SIZE-1)] = '\0';

	if(cmd)AT_TX_ECHO("%s",cat1_tx_buf);
	AT_RX_ECHO("%s",cat1_rx_buf);

	return cat1_rx_buf;
}

/**
 * @brief 向CAT1发送指令，并匹配响应
 *
 * @param cmd 要发送的AT指令
 * @param exp 期待响应
 * @param trials 尝试次数
 * @param timeout 每次尝试的响应接收超时
 *
 * @return int 状态
 * @retval 0 成功
 * @retval -1 超时
 */
int cat1_cmd_match_reply(const char cmd[], const char exp[], uint8_t trials, uint32_t timeout)
{
	char *reply;
	uint8_t try = 0;

	do
	{
		if(++try > trials)
		{
			//尝试次数过多
			DEBUG_PRINT("cmd_timeout(try%d)\r\n",try-1);
			return -1;
		}

		//发送命令
		reply = cat1_cmd(cmd,timeout);

		//响应关键字匹配
	}while(strstr(reply,exp)==NULL);

	return 0;
}

/**
 * @brief CAT1模块发送完成中断处理函数
 *
 * @note 请务必在HAL_UART_TxCpltCallback()回调中调用该函数！
 */
void cat1_tx_cplt_isr(void)
{
}

/**
 * @brief CAT1模块接收完成中断处理函数
 *
 * @note 请务必在HAL_UARTEx_RxEventCallback()回调中调用该函数！
 * @param size 已接收的数据大小
 */
void cat1_rx_cplt_isr(uint16_t size)
{
	//接收完成信号
	rx_cnt = size;
	osSignalSet(cat1TaskHandle, CAT1_SIGNAL_RX_CPLT);
}

/**
 * @brief 获取SIM卡状态
 *
 * @return 状态
 * @retval 0 READY		卡就绪
 * @retval 1 SIM PIN	需要密码
 * @retval 2 SIM PUK	需要密码
 * @retval 3 SIM PIN2	需要密码
 * @retval 4 SIM PUK2	需要密码
 * @retval 5 SIM REMOVED	未插卡
 * @retval -1 无响应
 */
int get_sim_card(void)
{
	char *reply;

	reply = cat1_cmd("AT+CPIN?\r\n", 1000);
	if((reply = strstr(reply,"+CPIN:"))!=NULL)
	{
		if(strstr(reply,"READY"))
		{
			return 0;
		}
		else if(strstr(reply,"SIM PIN"))
		{
			return 1;
		}
		else if(strstr(reply,"SIM PUK"))
		{
			return 2;
		}
		else if(strstr(reply,"SIM PIN2"))
		{
			return 3;
		}
		else if(strstr(reply,"SIM PUK2"))
		{
			return 4;
		}
		else if(strstr(reply,"SIM REMOVED"))
		{
			return 5;
		}
	}

	return -1;
}

/**
 * @brief 获取RSSI信号强度
 *
 * @return 信号强度
 * @retval 0 <= -115dBm
 * @retval 1 -111dBm
 * @retval 2~30 -109~-53dBm
 * @retval 31 >= -51dBm
 * @retval 99 未知或不可测
 * @retval -1 无响应
 * @retval -2 RSSI解析错误
 */
int get_rssi(void)
{
	char *reply;

	reply = cat1_cmd("AT+CSQ\r\n", 1000);
	if((reply = strstr(reply,"+CSQ"))!=NULL)
	{
		//找第一个数字
		while((*reply < '0')||(*reply > '9')) reply++;

		//找数字后的第一个逗号
		char *end = strchr(reply,',');
		if(end==NULL) return -2;

		//截取字符串，得到RSSI
		char tmp[5];
		memcpy(tmp,reply,end-reply);
		return atoi(tmp);
	}

	return -1;
}

/**
 * @brief 获取GPRS附着状态
 *
 * @return 附着状态
 * @retval 0 分离
 * @retval 1 附着
 * @retval -1 无响应
 */
int get_gprs_attach(void)
{
	char *reply;

	reply = cat1_cmd("AT+CGATT?\r\n", 1000);
	if(strstr(reply,"+CGATT: 0"))
	{
		return 0;
	}
	else if(strstr(reply,"+CGATT: 1"))
	{
		return 1;
	}

	return -1;
}


/**
 * @brief mqtt配置
 *
 * @param client_id 客户端ID
 * @param user_name 用户名
 * @param password 密码
 *
 * @return int 配置状态
 * @retval 0 配置成功
 * @retval -1 无响应
 */
int mqtt_config(const char client_id[], const char user_name[], const char password[])
{
	char *reply;
	sprintf(cat1_tx_buf,"AT+MCONFIG=%s,%s,%s\r\n",client_id,user_name,password);
	reply = cat1_cmd(cat1_tx_buf,1000);
	if(strstr(reply,"OK"))
	{
		return 0;
	}

	return -1;
}

/**
 * @brief 与MQTT Broker建立TCP连接
 *
 * @param broker 主机，可以是IP地址也可以是域名
 * @param port 端口
 *
 * @return 连接状态
 * @retval 0 CONNECT OK
 * @retval 1 ALREADY CONNECT
 * @retval 2 CONNECT FAIL
 * @retval -1 ERROR
 * @retval -2 无响应
 */
int mqtt_tcp_connect(const char broker[], uint16_t port)
{
	char *reply;
	sprintf(cat1_tx_buf,"AT+MIPSTART=%s,%d\r\n",broker,port);
	reply = cat1_cmd(cat1_tx_buf, 1000);
	if(strstr(reply,"OK"))
	{
		//等待URC
		int i=10;
		while(i--)
		{
			if(strstr(reply,"CONNECT OK"))
			{
				return 0;
			}
			else if(strstr(reply,"ALREADY CONNECT"))
			{
				return 1;
			}
			else if(strstr(reply,"CONNECT FAIL"))
			{
				return 2;
			}
			reply = cat1_cmd(NULL,1000);
		}
		return -2;
	}
	else if(strstr(reply,"ERROR"))
	{
		return -1;
	}
	return -2;
}

/**
 * @brief 关闭TCP连接
 *
 * @return 状态
 * @retval 0 成功
 * @retval -1 无响应
 */
int mqtt_tcp_close(void)
{
	char *reply;
	reply = cat1_cmd("AT+MIPCLOSE\r\n", 1000);
	if(strstr(reply,"OK"))
	{
		return 0;
	}

	return -1;
}

/**
 * @brief 与MQTT Broker建立会话连接
 *
 * @param clean_session 设为1时，抛弃以前的会话而建立一个新会话
 * @param keepalive 保活时间（秒），Broker在保活时间内未收到任何报文，则会断开连接，设备需要重连
 *
 * @return 连接状态
 * @retval 0 CONNACK OK
 * @retval -1 ERROR
 * @retval -2 无响应
 */
int mqtt_session_connect(uint8_t clean_session, uint16_t keepalive)
{
	char *reply;
	sprintf(cat1_tx_buf,"AT+MCONNECT=%d,%d\r\n",clean_session,keepalive);
	reply = cat1_cmd(cat1_tx_buf,1000);
	if(strstr(reply,"OK"))
	{
		return 0;
	}
	else if(strstr(reply,"ERROR"))
	{
		return -1;
	}
	return -2;
}

/**
 * @brief 断开会话连接
 *
 * @return 状态
 * @retval 0 成功
 * @retval -1 无响应
 */
int mqtt_session_disconnect(void)
{
	char *reply;
	reply = cat1_cmd("AT+MDISCONNECT\r\n",1000);
	if(strstr(reply,"OK"))
	{
		return 0;
	}
	return -1;
}

/**
 * @brief 获取MQTT连接状态
 *
 * @return int 连接状态
 * @retval 0 离线
 * @retval 1 已登录已认证，可以PUB消息
 * @retval 2 未认证，需要MCONNECT
 * @retval -1 无响应
 */
int mqtt_get_status(void)
{
	int i=3;
	while(i--)
	{
		char *reply;
		reply = cat1_cmd("AT+MQTTSTATU\r\n",300);
		reply = strstr(reply,"+MQTTSTATU :");
		if(reply)
		{
			return atoi(reply+strlen("+MQTTSTATU :"));
		}
	}
	return -1;
}

/**
 * @brief 订阅消息
 *
 * @param topic 要订阅的topic
 *
 * @return int 状态
 * @retval 0 订阅成功
 * @retval -1 订阅失败
 * @retval -2 缓存模式设置失败
 */
int mqtt_subscribe(const char topic[])
{
	char *reply;

	//设置为缓存模式
	reply = cat1_cmd("AT+MQTTMSGSET=1\r\n",1000);
	if(strstr(reply,"OK") == NULL)
	{
		return -2;
	}
	//订阅
	sprintf(cat1_tx_buf,"AT+MSUB=%s,0\r\n",topic);
	reply = cat1_cmd(cat1_tx_buf,1000);
	if(strstr(reply,"OK"))
	{
		return 0;
	}
	return -1;
}

/**
 * @brief 发布消息
 *
 * @param topic 要发布的topic
 * @param message 要发布的消息
 *
 * @return 状态
 * @retval 0 发布成功
 * @retval -1 发布失败
 */
int mqtt_publish(const char topic[], const char message[])
{
	char *reply;
	sprintf(cat1_tx_buf,"AT+MPUB=%s,0,0,\"%s\"\r\n",topic,message);
	reply = cat1_cmd(cat1_tx_buf, 1000);
	if(strstr(reply,"OK"))
	{
		return 0;
	}
	return -1;
}

//上报的模式
extern enum{SAFE,ALARM,RESCUE} mode;

/**
 * @brief 消息解释
 *
 * @param msg 消息字符串
 */
void message_parser(char *msg)
{
	JSONStatus_t result;
	size_t msgLen = strlen(msg);
	char *val;
	size_t valLen;

	//验证JSON格式
	result = JSON_Validate(msg, msgLen);
	if(result == JSONSuccess)
	{
		//匹配服务器主动下发指令

		//mode指令
		result = JSON_Search(msg,msgLen,"mode",4,&val,&valLen);
		if(result == JSONSuccess)
		{
			//判断是哪种mode
			if(strnstr(val,"safe",valLen))
			{
				osSignalSet(HMITaskHandle, SIGNAL_SAFE);
				return ;
			}
			if(strnstr(val,"alarm",valLen))
			{
				osSignalSet(HMITaskHandle, SIGNAL_ALARM);
				return ;
			}
			if(strnstr(val,"rescue",valLen))
			{
				osSignalSet(HMITaskHandle, SIGNAL_RESCUE);
				return ;
			}
		}

		//get指令
		result = JSON_Search(msg, msgLen, "get", 3, &val, &valLen);
		if(result == JSONSuccess)
		{
			if(strnstr(val,"mode",valLen))
			{
				//发送消息，报告当前模式
				if(publish_enable)
				{
					char *p = malloc(64);
					if(p)
					{
						switch(mode)
						{
						case SAFE:
							sprintf(p,"{\\\\22mode\\\\22:\\\\22safe\\\\22}");
							break;
						case ALARM:
							sprintf(p,"{\\\\22mode\\\\22:\\\\22alarm\\\\22}");
							break;
						case RESCUE:
							sprintf(p,"{\\\\22mode\\\\22:\\\\22rescue\\\\22}");
							break;
						}
						osMessagePut(publish_q_id, (uint32_t)p, 0);
					}
				}
				return;
			}

			if(strnstr(val,"cali",valLen))
			{
				//发送校准参数
				char *p = malloc(200);
				if(p)
				{
					if(config_is_valid())
					{
						const cali_t *pcali = &(pconfig->cali);
						snprintf(p,200,"{\\\\22cali\\\\22:{\\\\22pres\\\\22:{\\\\22a\\\\22:%.3f,\\\\22b\\\\22:%.3f},\\\\22volt\\\\22:{\\\\22a\\\\22:%.3f,\\\\22b\\\\22:%.3f},\\\\22antdly\\\\22:{\\\\22tx\\\\22:%d,\\\\22rx\\\\22:%d}}}",
								pcali->pres_a, pcali->pres_b,
								pcali->volt_a, pcali->volt_b,
								pcali->tx_ant_dly,pcali->rx_ant_dly);
					}
					else
					{
						snprintf(p,200,"{\\\\22cali\\\\22:\\\\22invalid\\\\22}");
					}
					osMessagePut(publish_q_id, (uint32_t)p, 0);
				}
			}
		}

		//cali指令
		result = JSON_Search(msg, msgLen, "cali", 4, &val, &valLen);
		if(result == JSONSuccess)
		{
			char *v;
			size_t n;
			config_t cfg;
			memcpy(&cfg,pconfig,sizeof(config_t));
			cfg.cali.pres_a = 1.0;
			cfg.cali.pres_b = 0.0;
			cfg.cali.volt_a = 1.0;
			cfg.cali.volt_b = 0.0;
			cfg.cali.rx_ant_dly = 16436;
			cfg.cali.rx_ant_dly = 16436;

			if(JSONSuccess == JSON_Search(val,valLen,"pres",4,&v,&n))
			{
				char *vv;
				size_t nn;
				if(JSONSuccess == JSON_Search(v,n,"a",1,&vv,&nn))
					cfg.cali.pres_a = atof(vv);
				if(JSONSuccess == JSON_Search(v,n,"b",1,&vv,&nn))
					cfg.cali.pres_b = atof(vv);
			}
			if(JSONSuccess == JSON_Search(val,valLen,"volt",4,&v,&n))
			{
				char *vv;
				size_t nn;
				if(JSONSuccess == JSON_Search(v,n,"a",1,&vv,&nn))
					cfg.cali.volt_a = atof(vv);
				if(JSONSuccess == JSON_Search(v,n,"b",1,&vv,&nn))
					cfg.cali.volt_b = atof(vv);
			}
			if(JSONSuccess == JSON_Search(val,valLen,"antdly",6,&v,&n))
			{
				char *vv;
				size_t nn;
				if(JSONSuccess == JSON_Search(v,n,"tx",2,&vv,&nn))
					cfg.cali.tx_ant_dly = atoi(vv);
				if(JSONSuccess == JSON_Search(v,n,"rx",2,&vv,&nn))
					cfg.cali.rx_ant_dly = atoi(vv);
			}

			int8_t res = config_device(&cfg);
			DEBUG_PRINT("config %s (%d)\r\n",res?"failed":"successed",res);
			return ;
		}

		//reset指令
		result = JSON_Search(msg, msgLen, "reset", 5, &val, &valLen);
		if(result == JSONSuccess)
		{
			uint32_t rst_dly = atoi(val);
			osDelay(rst_dly);
			HAL_NVIC_SystemReset();
		}
	}
}

/**
 * @brief 发布消息处理
 *
 * @return 状态
 * @retval 0 消息发布成功，或无消息需要发布
 * @retval -1 处理错误
 */
int8_t publish_handler()
{
	//等待发布队列
	osEvent evt = osMessageGet(publish_q_id, 50);
	if(evt.status == osEventMessage)
	{
		//将队列中的所有消息发送完
		do
		{
			uint8_t ret;
			//发布并释放一条消息
			ret = mqtt_publish(DEVICE_PUB_TOPIC, evt.value.p);
			free(evt.value.p);
			if(ret)
			{
				DEBUG_PRINT("publish failed!\r\n");
				return -1;
			}
			evt = osMessageGet(publish_q_id, 0);
		}while(evt.status == osEventMessage);
	}
	return 0;
}

/**
 * @brief 订阅消息处理
 *
 * @return 状态
 * @retval 0 订阅消息处理正常，或者无订阅消息需要处理
 * @retval -1 处理错误
 */
int8_t subscribe_handler(void)
{
	char *reply;

	//检查是否有缓存的消息
	reply = cat1_cmd_to("AT+MQTTMSGGET\r\n", 50);
	while((reply = strstr(reply,"+MSUB:"))!=NULL)
	{
		char *end = strchr(reply,'\r');

		if(!end) break;

		if(reply = strchr(reply,',')) reply++;
		else break;

		if(reply = strchr(reply,',')) reply++;
		else break;

		*end = 0;

		message_parser(reply);
		DEBUG_PRINT("MSG %s\r\n",reply);
		reply = end+1;
	}
	return 0;
}

/**
 * @brief 初始化CAT1模块，对模块进行硬复位和握手
 * 
 * @return int8_t 操作状态
 * @retval 0 成功
 * @retval -1 等待模块就绪超时
 * @retval -2 AT握手失败
 * @retval -3 关闭AT回显失败
 */
static int8_t cat1_init_at(void)
{
	DEBUG_PRINT("INIT AT\r\n");

	//上电复位
	HAL_GPIO_WritePin(CAT1_EN_GPIO_Port,CAT1_EN_Pin, GPIO_PIN_SET);
	osDelay(50);
	HAL_GPIO_WritePin(CAT1_EN_GPIO_Port,CAT1_EN_Pin, GPIO_PIN_RESET);
	osDelay(500);

	//等待模块就绪
	if(cat1_cmd_match_reply(NULL, "RDY", 3, 3000))
	{
		return -1;
	}

	//AT握手
	if(cat1_cmd_match_reply("AT\r\n", "OK", 5, 500))
	{
		return -2;
	}

	//关闭回显
	if(cat1_cmd_match_reply("ATE0\r\n", "OK", 5, 1000))
	{
		return -3;
	}

	return 0;
}

/**
 * @brief 网络初始化
 * 
 * @return int8_t 操作状态
 * @retval 0 成功
 * @retval -1 检查SIM卡失败
 * @retval -2 查询信号质量失败
 * @retval -3 查询GPRS附着状态失败
 */
static int8_t cat1_init_network(void)
{
	DEBUG_PRINT("INIT NETWORK\r\n");

	//检查SIM卡
	while(1)
	{
		int st = get_sim_card();
		if(st==0)
		{
			DEBUG_PRINT("SIM CARD READY\r\n");
			break;
		}
		else if(st > 0)
		{
			DEBUG_PRINT("SIM CARD INVALID(%d),PLEASE CHECK\r\n",st);
			DEBUG_PRINT("retry after 5s...\r\n");
			osDelay(5000);
		}
		else
		{
			return -1;
		}
	}

	//查询信号质量
	while(1)
	{
		int rssi = get_rssi();
		if(10<=rssi && rssi<=31)
		{
			DEBUG_PRINT("RSSI %d\r\n",rssi);
			break;
		}
		else if(rssi>0)
		{
			DEBUG_PRINT("RSSI INVALID(%d)\r\n",rssi);
			DEBUG_PRINT("retry after 1s...\r\n");
			osDelay(1000);
		}
		else
		{
			return -2;
		}
	}

	//查询GPRS附着状态
	while(1)
	{
		int ret = get_gprs_attach();
		if(ret == 1)
		{
			DEBUG_PRINT("GPRS ATTACH\r\n");
			break;
		}
		else if(ret == 0)
		{
			DEBUG_PRINT("GPRS DETACH\r\n");
			DEBUG_PRINT("retry after 5s...\r\n");
			osDelay(5000);
		}
		else
		{
			return -3;
		}
	}

	return 0;
}

/**
 * @brief MQTT初始化
 *
 * @return int8_t 操作状态
 * @retval 0 成功
 * @retval -1 mqtt配置失败
 * @retval -2 broker连接失败
 * @retval -3 会话建立失败
 * @retval -4 未知错误
 */
int8_t cat1_init_mqtt(void)
{
	int ret;

	//配置MQTT客户端参数
	if(mqtt_config(CLIENT_ID,USER_NAME,PASSWORD))
	{
		return -1;
	}

	//连接Broker
	while(1)
	{
		switch(mqtt_tcp_connect(BROKER_HOST,BROKER_PORT))
		{
		case 0:
			ret = mqtt_session_connect(0, 300);
			if(ret == 0)
			{
				return 0;
			}
			DEBUG_PRINT("MQTT SESSION CONNECT FAILED(%d)\r\n",ret);
			mqtt_session_disconnect();
			DEBUG_PRINT("MQTT SESSION DISCONNECTED\r\n");
		case 1:
			mqtt_tcp_close();
			DEBUG_PRINT("MQTT TCP CLOSED\r\n");
		case 2:
			DEBUG_PRINT("retry after 1s...\r\n");
			osDelay(1000);
			break;
		default :
			return -2;
		}
	}

	return -4;
}

/**
 * @brief 运行MQTT订阅/发布服务
 *
 * @return MQTT连接状态，参考mqtt_get_status()
 * @retval -1 订阅失败
 * @retval -2 发布失败
 */
int8_t cat1_mqtt_service(void)
{
	int ret;

	//订阅Topic
	osDelay(1000);
	if(mqtt_subscribe(DEVICE_SUB_TOPIC))
	{
		return -1;
	}

	//发布设备上线消息
	if(mqtt_publish(DEVICE_PUB_TOPIC,MSG_DEVICE_ONLINE))
	{
		return -2;
	}

	//处理发布和订阅
	DEBUG_PRINT("MQTT SERVICE RUNNING\r\n");
	publish_enable = 1;
	osSignalSet(HMITaskHandle, SIGNAL_MQTT_ONLINE);
	ret = mqtt_get_status();
	while(ret == 1)
	{
		//等待发布队列
		if(publish_handler())
		{
			ret = mqtt_get_status();
		}
		//查询订阅消息
		if(subscribe_handler())
		{
			ret = mqtt_get_status();
		}
#ifdef PRESSURE_STATION
		extern osThreadId presTaskHandle;
		//关机
		osEvent evt = osSignalWait(CAT1_SIGNAL_POWERDOWN, 0);
		if(evt.status == osEventSignal)
		{
			DEBUG_PRINT("CAT1 Power Down...\r\n");
			osDelay(1000);
			cat1_cmd("AT+CPOWD=0\r\n",1000);
			osSignalSet(presTaskHandle, CAT1_SIGNAL_POWERDOWN_OK);
		}
#endif
	}

	DEBUG_PRINT("MQTT SERVICE EXIT\r\n");
	publish_enable = 0;
	osSignalSet(HMITaskHandle, SIGNAL_MQTT_OFFLINE);
	return ret;
}

void StartCAT1Task(void const * argument)
{
	int8_t ret;

	publish_q_id = osMessageCreate(osMessageQ(publish_q), NULL);

	/**
	 * AT指令初始化
	 * 确保串口AT指令可以正常与模块通信
	 */
	while((ret = cat1_init_at()) == 0)
	{
		DEBUG_PRINT("INIT AT OK\r\n");
		/**
		 * 网络初始化
		 * 确保运营商网络服务正常
		 */
		while((ret = cat1_init_network())==0)
		{
			DEBUG_PRINT("INIT NETWORK OK\r\n");
			/**
			 * mqtt初始化
			 * 确保与broker连接正常
			 */
			while((ret = cat1_init_mqtt())==0)
			{
				DEBUG_PRINT("INIT MQTT OK\r\n");
				/**
				 * mqtt订阅/发布
				 * 开始处理其他task的发布请求，并解析收到的订阅消息
				 */
				ret = cat1_mqtt_service();
				DEBUG_PRINT("EXIT MQTT SERVICE(%d)\r\n",ret);
				DEBUG_PRINT("try after 5s...\r\n");
				osDelay(5000);
			}
			DEBUG_PRINT("INIT MQTT FAILED(%d)\r\n",ret);
			DEBUG_PRINT("try after 5s...\r\n");
			osDelay(5000);
		}
		DEBUG_PRINT("INIT NETWORK FAILED(%d)\r\n",ret);
		DEBUG_PRINT("try after 5s...\r\n");
		osDelay(5000);
	}

	//AT指令无法工作，请检查硬件
	PRINT("INIT AT FAILED\r\n");
	Error_Handler();
}
